<?php
/**
 * 
 * Copyright (c) 2008 Jerry Jalava <jerry.jalava@gmail.com>
 * Licensed under the GPLv3 license
 * http://www.gnu.org/licenses/gpl.html
 * 
 */

class couchdb_documents_document extends couchdb_transport
{
    protected $id = null;
    protected $rev = null;
        
    private $object = null;
    
    public function __construct($id=null, $configuration=array(), $db_object=null)
    {
        if (   is_null($id)
            || empty($id))
        {
            throw new couchdb_document_exception('No id given!');
        }

        parent::__construct($configuration);
        
        $this->id = $id;
        
        if (! is_null($db_object))
        {
            $this->set_object_from_db($db_object);
        }
    }
    
    public function __get($key)
    {        
        switch ($key)
        {
            case 'stdObject':                
                return $this->read_object();
            break;
            default:
                return $this->read_object($key);
        }
    }
    
    public function __set($key, $value)
    {
        return $this->update_object($key, $value);
    }
    
    public function __isset($key)
    {
        return $this->object_has_key($key);
    }
    
    public function &exists($id=null, $force_reload=false)
    {        
        if (is_null($id))
        {
            $id = $this->id;
        }
        
        if (   (   !is_null($this->object)
                && $this->object->id == $id)
            && !$force_reload)
        {
            return $this;
        }
        
        try
        {
            $this->set_object_from_db( $this->execute("{$id}") );
            return $this;
        }
        catch (couchdb_transport_exception $e)
        {
            if ($e->getCode() == 404)
            {
                throw new couchdb_document_exception("Document {$id} not found.", 404);                
            }
            
            throw $e;
        }
        
        return false;
    }
    
    public function &save()
    {
        $results = $this->execute("{$this->id}", 'PUT', $this->toString());
        
        $this->set_object_from_db( $this->execute("{$this->id}") );
        
        return $results;
    }
    
    public function delete($id=null, $rev=null)
    {
        if (is_null($id))
        {
            $id = $this->id;
        }
        if (is_null($rev))
        {
            $rev = $this->rev;
        }
        
        $suffix = '';
        if (! is_null($rev))
        {
            $suffix = "?rev={$rev}";
        }
        
        return $this->execute("{$id}{$suffix}", 'DELETE');
    }
    
    public function &get($id=null)
    {
        $this->exists($id, true);
        return $this;
    }
    
    public function toString()
    {
        return json_encode($this->object);
    }
    
    private function set_object_from_db($object)
    {
        if (isset($this->object->_rev))
        {
            $thid->rev = $object->_rev;
        }
        
        $this->object = $object;
    }
    
    private function object_has_key($key)
    {
        if (isset($this->object->$key))
        {
            return true;
        }
        
        return false;
    }
    
    private function read_object($key=null)
    {        
        if (is_null($this->object))
        {
            try
            {
                $this->exists();
            }
            catch(couchdb_document_exception $e)
            {
                if ($e->getCode() == 404)
                {
                    $this->generate_object();
                }
            }
        }
        
        if (! is_null($key))
        {
            if (! isset($this->object->$key))
            {
                throw new couchdb_document_exception("Document key {$key} doens't exist!");
            }
            
            return $this->object->$key;
        }
        
        return $this->object;
    }
    
    private function update_object($key, $value)
    {
        if (   $key != '_id'
            && $key != '_rev')
        {
            $this->object->$key = $value;            
        }
    }
    
    private function generate_object()
    {
		$obj = new stdClass;
		foreach (get_object_vars($this) as $attr => $value) {
		    if (   $attr != 'object'
		        && $attr != 'id'
		        && $attr != 'rev')
		    {
    			$obj->$attr = $value;
		    }
		}
		
		if (! is_null($this->id))
		{
			$obj->_id = $this->id;
		}
		
		if (! is_null($this->rev))
		{
			$obj->_rev = $this->rev;
		}

		$this->object = $obj;
    }
}

?>